package com.wolfman.wolfchat.component;

import com.alibaba.fastjson.JSON;
import com.wolfman.wolfchat.annotation.NeedAuthentication;
import com.wolfman.wolfchat.po.Message;
import com.wolfman.wolfchat.po.User;
import com.wolfman.wolfchat.service.MessageService;
import com.wolfman.wolfchat.service.UserService;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;


/**
 * @Title
 * @Description
 * @Author WolfMan
 * @Date 2022/1/14 14:40
 * @Email 2370032534@qq.com
 */
@Component
@ServerEndpoint(value = "/wolfchat/{userId}")
public class WebSocketServer {

    /**
     * 记录当前在线连接数
     */
    public static final Map<Integer, Session> sessionMap = new ConcurrentHashMap<>();

    /**
     * 记录当前在线用户信息
     */
    public static final Map<Integer, User> userMap = new ConcurrentHashMap<>();

    /**
     * 用于查询用户
     */
    public static UserService userService;

    /**
     * 用于持久化消息
     */
    public static MessageService messageService;

    /**
     * 连接建立成功调用的方法
     *
     * @param session
     * @param userId
     */
    @OnOpen
    @NeedAuthentication
    public void onOpen(Session session, @PathParam("userId") Integer userId) throws IOException {
        User user = userService.selectByUserId(userId);
        if (user == null) {
            return;
        }
        //加入当前在线链接用户
        userMap.put(userId, user);
        sessionMap.put(userId, session);
        // 后台发送消息给所有的客户端
        sendMessageToAll();
    }


    /**
     * 连接关闭调用的方法
     */
    @OnClose
    @NeedAuthentication
    public void onClose(@PathParam("userId") Integer userId) throws IOException {
        userMap.remove(userId);
        sessionMap.remove(userId);
        //推送最新在线信息
        sendMessageToAll();
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param content
     */
    @OnMessage
    @NeedAuthentication
    public void onMessage(String content) throws IOException {
        Message message = JSON.parseObject(content, Message.class);
        User u = userService.selectByUserId(message.getToUserId());
        //用户不存在
        if (u == null) {
            return;
        }
        //不是系统消息
        message.setIsSystem(false);
        //保存到数据库
        message.setCreateTime(new Date());
        messageService.save(message);
        // 根据 to用户名来获取 session，再通过session发送消息文本
        Session targetSession = sessionMap.get(message.getToUserId());
        if (targetSession == null) {
            return;
        }
        //重新构建消息
        User fromUser = userMap.get(message.getFromUserId());
        HashMap<String, Object> map = new HashMap<>(2);
        map.put("fromUser", fromUser);
        map.put("message", message.getMessage());
        message.setMessage(JSON.toJSONString(map));
        sendMessageToOne(message, targetSession);
    }

    /**
     * 连接错误调用的方法
     *
     * @param error
     */
    @OnError
    @NeedAuthentication
    public void onError(Throwable error) {
        error.printStackTrace();
    }

    /**
     * 向所有用户发送信息
     *
     * @throws IOException
     */
    private void sendMessageToAll() throws IOException {
        List<User> userList = new ArrayList<>(userMap.values());
        Message message = new Message();
        //是系统消息
        message.setIsSystem(true);
        message.setMessage(JSON.toJSONString(userList));
        for (Session session : sessionMap.values()) {
            sendMessageToOne(message, session);
        }
    }

    /**
     * 向某个用户发送信息
     *
     * @param message
     * @param targetSession
     */
    private synchronized void sendMessageToOne(Message message, Session targetSession) throws IOException {
        targetSession.getBasicRemote().sendText(JSON.toJSONString(message));
    }

}

